/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ************************************************************************************************
 * @file     Mram_Ip.h                                                                       *
 * @brief    This file contains interface header for MRAM IP driver, ...                         *
 * @author   Department/Semidrive                                                                  *
 * @date     2024/10/16                                                                            *
 *                                                                                                 *
 **************************************************************************************************/

#ifndef MRAM_IP_H
#define MRAM_IP_H

#include <debug.h>
#include "lld_platform.h"

#ifdef __cplusplus
extern "C" {
#endif

/* PRQA S 0306,0315,0314,0326,0750,3116,3673 EOF */

#ifndef MRAM_USE_APB2TMB
#define MRAM_USE_APB2TMB 0
#endif

#ifndef CONFIG_WITH_MRAM_DEBUG
#define CONFIG_WITH_MRAM_DEBUG 0
#endif

#ifndef CONFIG_MRAM_SUPPORT_UNTRIMMED_CHIP
#define CONFIG_MRAM_SUPPORT_UNTRIMMED_CHIP 0
#endif

#if defined (CFG_PLATFORM_SSDK)
#include <string.h>
#define MRAM_MEMCLR(dst, size)          memset(dst, 0x0u, size)

#if (CONFIG_WITH_MRAM_DEBUG)
#include <debug.h>
#define MRAM_LOG_DEBUG(x...) ssdk_printf(SSDK_DEBUG,x)
#define MRAM_LOG_ERROR(x...) ssdk_printf(SSDK_ERR,x)
#else
#define MRAM_LOG_DEBUG(...)
#define MRAM_LOG_ERROR(...)
#endif

#elif defined (CFG_PLATFORM_MCAL)
#include <Mcal_MemLibc.h>
#define MRAM_MEMCLR(dst, size)          Mcal_MemClr(dst, size)

#if (CONFIG_WITH_MRAM_DEBUG)
#include <debug.h>
#define MRAM_LOG_DEBUG(x...) DBG(x)
#define MRAM_LOG_ERROR(x...) ERROR(x)
#else
#define MRAM_LOG_DEBUG(...)
#define MRAM_LOG_ERROR(...)
#endif

#else
#error "Undefined macros CFG_PLATFORM_MCAL or CFG_PLATFORM_SSDK"
#endif /** #if defined (CFG_PLATFORM_MCAL) */

/***************************************************************************************************
 *                                 Global Macro definition
 **************************************************************************************************/
#define MRAM_ECC_ERROR_ADDRESS_MAX (8u)

#define MRAM_BIT(nr) ((uint32_t)1u << (nr))
#define MRAM_DIV_ROUND_UP(n,d) (((n) + (d) - 1U) / (d))
#define MRAM_ROUNDUP(a, b) (((a) + ((uint32_t)(b)-1U)) & ~((uint32_t)(b)-1U))
#define MRAM_ROUNDDOWN(a, b) ((a) & ~((uint32_t)(b)-1U))
#define MRAM_IS_ALIGNED(a, b) (0U == (((uint32_t)(a)) & (((uint32_t)(b))-1U)))
#define MRAM_MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MRAM_MAX(a, b) (((a) > (b)) ? (a) : (b))

#define MRAM_RET_OK                     (0)
#define MRAM_RET_FAILED                 (-1)
#define MRAM_RET_PARAMETER_ERR          (-2)
#define MRAM_RET_BOUND_ERR              (-3)
#define MRAM_RET_CRC_ERR                (-4)
#define MRAM_RET_TIMEOUT                (-5)
#define MRAM_RET_UNSUPPORT              (-6)

#define MRAM_TYPE_32M_SIZE_BYTE         (0x400000u)         /* main block size of Mram32mb macro */
#define MRAM_TYPE_4M_SIZE_BYTE          (0x80000u)          /* main block size of Mram4mb macro */
#define MRAM_SUB_BANK_SIZE_BYTE         (0x80000u)
#define MRAM_WORD_SIZE_BYTE             (0x10u)             /* a mram word size of mram macro */

#define MRAM_IMG_CRC_AUTO_INDEX         (0xFFu)

#define MRAM_RDBUFFER_IGNOR_IDENT       (0xFFFFu)           /* If this parameter is used in the configuration, the current id is ignored */

#define MRAM_EVENT_ERROR                MRAM_BIT(31)        /* Unexpected error */
#define MRAM_EVENT_ECC_NEED_REPAIR      MRAM_BIT(0)         /* The Ecc error record is full and needs to be fixed immediately */
#define MRAM_EVENT_PGLOCK_AREA_DENY     MRAM_BIT(1)         /* The write protected area is accessed. Procedure */
#define MRAM_EVENT_MEMORY_DAMAGED       MRAM_BIT(2)         /* Memory is irreparably damaged */
#define MRAM_EVENT_CRC_CHECK_ERROR      MRAM_BIT(3)         /* A crc check error occurred */

#define  MRAM_TYPE_32M                  (0u)    /* Mram32mb macro has 4MB main block non-volatile memory. */
#define  MRAM_TYPE_4M                   (1u)    /* Mram4mb macro has 512KB main block non-volatile memory. */

typedef enum {
    MRAM_UNINIT = 0,
    MRAM_READY,
    MRAM_DEFECTIVE
} Mram_StatusType;

typedef enum {
    MRAM_TMC_CMD_TYPE_READ = 0u,            /* Read the Main-Block of mram macro */
    MRAM_TMC_CMD_TYPE_WRITE,                /* Write the Main-Block of mram macro */
    MRAM_TMC_CMD_TYPE_READ_REG32,           /* Read the register of tmc */
    MRAM_TMC_CMD_TYPE_WRITE_REG32,          /* Write the register of tmc */
/* only for internal use */
#if MRAM_USE_APB2TMB
    MRAM_TMC_CMD_TYPE_READ_BIST,
    MRAM_TMC_CMD_TYPE_WRITE_BIST,
    MRAM_TMC_CMD_TYPE_READ_REG32_BIST,
    MRAM_TMC_CMD_TYPE_WRITE_REG32_BIST,
#endif /* #if MRAM_USE_APB2TMB */
} Mram_TmcCmdType;

typedef enum {
    MRAM_BLOCK_TYPE_MAIN = 0,           /* The Main-Block is the main area for function data storage. */
    MRAM_BLOCK_TYPE_INFO_USER,          /* The INFO-User-Block is used as redundancy area for row repair. User may disregard this area. */
    MRAM_BLOCK_TYPE_INFO_MARCO,         /* The INFO1-Marco-Block is mainly used for test. User may disregard this area. */
    MRAM_BLOCK_TYPE_OTP_USER,           /* The OTP-User-Block is reserved for future requirement. User may disregard this area. */
    MRAM_BLOCK_TYPE_OTP_MARCO,          /* The OTP1-Marco-Block is completely used for test. User may disregard this area. */
    MRAM_BLOCK_TYPE_OTP_USER_2P2V,      /* Burn mode OTP-User-Block */
    MRAM_BLOCK_TYPE_OTP_MARCO_2P2V      /* Burn mode OTP1-Marco-Block */
} Mram_BlockType;

typedef enum {
    MRAM_IMG_CRC_CHK_INVALID = 0,       /* Invalid the region */
    MRAM_IMG_CRC_CHK_STOP,              /* Stop check */
    MRAM_IMG_CRC_CHK_ONESHOT,           /* Check once and return results immediately */
    MRAM_IMG_CRC_CHK_LOOP,              /* Background loop check, get results through interrupt or active interface */
} Mram_CrcCheckModeType;

typedef enum {
    MRAM_FLUSH_ONLY_CURRENT = 0,        /* Only the existing ones in the current buffer are refreshed */
    MRAM_FLUSH_UNTIL_EMPTY,             /* Refresh buffer until buffer is empty */
    MRAM_FLUSH_UNTIL_EMPTY_AND_SUSPEND  /* Refresh buffer until buffer is empty, And block new writes to wrbuf */
} Mram_FlushModeType;

typedef unsigned int   Mram_BitFieldType;

/* Several ways to represent an mram address */
typedef union {
    uint32_t data;
    struct {
        Mram_BitFieldType wordAddress: 20;
        Mram_BitFieldType reserved: 12;
    } address;
    struct {
        Mram_BitFieldType yAddress: 5;
        Mram_BitFieldType xAddress3To0: 4;
        Mram_BitFieldType xAddress9To4: 6;
        Mram_BitFieldType bAddress: 3;
        Mram_BitFieldType reserved: 14;
    } original32MAddress;
    struct {
        Mram_BitFieldType yAddress: 5;
        Mram_BitFieldType xAddressBit0: 1;
        Mram_BitFieldType xAddress9To1: 9;
        Mram_BitFieldType reserved: 17;
    } original4MAddress;
    struct {
        Mram_BitFieldType yAddress: 5;
        Mram_BitFieldType xAddress9To4: 6;
        Mram_BitFieldType bAddress: 3;
        Mram_BitFieldType xAddress3To0: 4;
        Mram_BitFieldType reserved: 14;
    } interleaved32MAddress;
    struct {
        Mram_BitFieldType yAddress: 5;
        Mram_BitFieldType xAddress9To1: 9;
        Mram_BitFieldType xAddressBit0: 1;
        Mram_BitFieldType reserved: 17;
    } interleaved4MAddress;
} Mram_WordAddressType;

typedef struct {
    bool invalidFlag;
    Mram_WordAddressType mramWordAddress;
} Mram_EccErrorAddressType;

typedef struct {
    Mram_BlockType type;        /* The type of block*/
    uint32_t addr;              /* The address unit is Byte, 1 word=16 Bytes */
    uint8_t *buffer;            /* uint8_t buffer[16] alloc by user, 128bits */

    /* output */
    uint32_t info;
} Mram_TmcRdWrWordCfgType;

typedef struct {
    uint32_t addr;
    uint32_t regValue;
} Mram_TmcRdWrRegCfgType;

typedef struct {
    Mram_TmcCmdType type;
    union {
        Mram_TmcRdWrWordCfgType rdWrWordCfg;
        Mram_TmcRdWrRegCfgType rdWrRegCfg;
    } param;
} Mram_TmcCmdCfgType;

typedef struct {
    uint8_t channelId;
    uint16_t masterId;   /* valid_bits[4:0] */
    uint16_t arid;        /* valid_bits[7:0] */
    bool enable;
} Mram_RdBufferCfgType;

typedef struct {
    uint8_t index;
    bool valid;
    uint32_t address;
    uint32_t size;
    uint32_t crcExpval;
} Mram_ImageCrcCfgType;

typedef struct {
    uint8_t phaseRevision;
    uint8_t minorRevision;
    uint8_t majorRevision;
    uint8_t mramVersion;
    uint32_t totalSize;
} Mram_InfoType;

typedef enum {
    MRAM_INIT_RST_AUTO_WAKEUP = 0u,
    MRAM_INIT_SW_AUOTO_WAKEUP,
    MRAM_INIT_BYPASS,
    MRAM_INIT_UNTRIMMED_SW_WAKEUP,
} Mram_InitialModeType;

/***************************************************************************************************
 *                                  Global Types definition                                        *
 **************************************************************************************************/
struct Mram_Host;

/* External Dependency Function Registration */
typedef void Mram_EventListenerType(void *arg, uint32_t event);

typedef struct {
    /* Basic Information */
    uint32_t apbBase;           /* The address to access the controller register */
    uint32_t axiRdBase;         /* base address of read data */
    uint32_t axiWrBase;         /* base address for writing data */
    uint32_t irq;               /* Interrupt number, not used at the LLD, reserved */

    /* function switch */
    Mram_InitialModeType initialMode;   /* Initialize the mode */
    bool interleaveDis;    /* Get by fuse bit */
} Mram_HostStaticConfigType;

typedef struct {
    /* Static configuration parameters */
    Mram_HostStaticConfigType config;

    /* Dynamically adjustable parameters */
    uint32_t aclkHz;        /* bus clock frequency, specified externally, used to calculate the internal partial frequency */
    uint32_t tmcClkHz;      /* The clock frequency of the tmc interface */
    uint8_t wrIntervalUs;   /* The cooldown time for writing */
    bool wrBufferEnable;    /* Switch of wrbuffer */
} Mram_HostConfigType;

typedef struct Mram_Host {
    /* Static config */
    Mram_HostStaticConfigType config;

    /* function switch */
    bool wrBufferEnable;        /* Switch status of wrbuffer */
    bool useInterrupt;          /* The usage status of an interrupt */

    /* runtime variables*/
    uint8_t index;              /* The index of controller at the upper layer */
    uint32_t base;              /* The logical address of controller at the upper layer */
    uint64_t pglkPassword;      /* The current key used for write protection */
    uint8_t wrIntervalUs;       /* Write cooldown time currently in use */
    uint32_t aclkHz;            /* AXI bus clock currently used to calculate frequency division */
    uint32_t tmcClkHz;          /* Clock frequency of the current tmc interface */
    uint32_t dmaMaxSize;        /* Clock frequency of the current tmc interface */
    Mram_InfoType info;         /* Version and size information */
    Mram_StatusType status;     /* Controller global state */
    Mram_EventListenerType *eventListener;  /* Event listening callback interface */
    void *eventListenerArg;     /* Listen for callback parameters */
    Mram_EccErrorAddressType eccErrAddrTable[MRAM_ECC_ERROR_ADDRESS_MAX]; /* Error address recorded */
    uint8_t eccErrAddrNum;      /* The number of error addresses recorded */
    void *parent;               /* Pointers to the superstructure */
} Mram_HostType;

/***************************************************************************************************
 *                                  Global Function Declarations                                   *
 **************************************************************************************************/
int32_t Mram_HostIrqHandler(uint32_t irq, void *arg);

int32_t Mram_HostInit(Mram_HostType *host, const Mram_HostConfigType *config);

int32_t Mram_HostTmcClkSetup(Mram_HostType *host, uint32_t tmcClk);

void* Mram_HostMemcopy(void *dst, const void *src, uint32_t totalSize);

int32_t Mram_HostEccRepair(Mram_HostType *host);

int32_t Mram_HostRdBufferSetup(Mram_HostType *host, const Mram_RdBufferCfgType* rdbufferCfg, uint8_t num);

int32_t Mram_HostGetValidImageRgnIndex(Mram_HostType *host, uint8_t *index);

int32_t Mram_HostImageCrcSetup(Mram_HostType *host, const Mram_ImageCrcCfgType *cfg);

int32_t Mram_HostImageCrcCheckStart(Mram_HostType *host, uint8_t index, Mram_CrcCheckModeType mode);

int32_t Mram_HostGetCrcCheckStatus(Mram_HostType *host, uint8_t index);

int32_t Mram_HostSendTmc(Mram_HostType *host, Mram_TmcCmdCfgType* tmcCfg);

int32_t Mram_HostWrBufferFlush(Mram_HostType *host, Mram_FlushModeType mode);

int32_t Mram_HostRefCellRewriteEnable(Mram_HostType *host);

int32_t Mram_HostRdBufferInvalidate(Mram_HostType *host);

int32_t Mram_HostProtectSetup(Mram_HostType *host, uint32_t addr, uint32_t size, bool enable);

uint32_t Mram_HostEccErrAddrConvert(Mram_HostType *host, Mram_WordAddressType wordAddr);

void Mram_HostDeinit(Mram_HostType *host);

uint32_t Mram_HostGetWrbufferEntry(Mram_HostType *host);

int32_t Mram_HostRead(Mram_HostType *host, uint32_t address, uint8_t* buf,uint32_t size);

int32_t Mram_HostWrite(Mram_HostType *host, uint32_t address, const uint8_t* buf,uint32_t size);

int32_t Mram_HostEventSetup(Mram_HostType *host, Mram_EventListenerType *eventListener,
        void *eventListenerArg);

#ifdef __cplusplus
}
#endif
#endif /* MRAM_IP_H */

/* End of file */
